package com.hanlin.beforejavacodesummary;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.PictureType;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.hanlin.beforejavacodesummary.pojo.otherentry.po.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.*;
import org.w3c.dom.Document;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@SpringBootTest
public class XmlToWordProcessor_V1 {
    @Test
    public void mainTest() throws Exception {

        String xmlPath = "E:\\personCode\\LiJingJavaCodeAddress\\beforeJavaCodeSummary\\src\\main\\resources\\templates\\1.xml";
        String templatePath = "templates/报告模板-v3.docx";
        String outputPath = "E:\\personCode\\LiJingJavaCodeAddress\\beforeJavaCodeSummary\\src\\main\\resources\\templates";

        KbReportMap kbReportMap = new KbReportMap();
        // 解析XML并提取数据
        ReportBasicsData baseData = parseXmlToMap(xmlPath);

        kbReportMap.setStationName(baseData.getStationName());
        kbReportMap.setEventDateYmd(baseData.getEventDateYmd());
        kbReportMap.setEventDateTime(baseData.getEventDateTime());
        kbReportMap.setFaultDesc(baseData.getFaultDesc());
        kbReportMap.setOperationMode(baseData.getOperationMode());
        kbReportMap.setVoltageMode(baseData.getVoltageMode());
        kbReportMap.setDcpower(baseData.getDcpower());
        kbReportMap.setPowerLoss(baseData.getPowerLoss());

        // 读取事件列表
        List<Map<String, String>> eventList = parseEventList(xmlPath);

        List<EventDO> newEventList = new ArrayList<>();
        for (int i = 0; i < eventList.size(); i++) {
            Map<String, String> stringStringMap = eventList.get(i);
            EventDO eventDO = new EventDO();
            eventDO.setTime(stringStringMap.get("time"));
            eventDO.setTimeValue(stringStringMap.get("time_value"));
            eventDO.setHhmmssMs(stringStringMap.get("hhmmss_ms"));
            eventDO.setSystemId(stringStringMap.get("system_id"));
            eventDO.setMainCpu(stringStringMap.get("main_cpu"));
            eventDO.setEventText(stringStringMap.get("event_text"));
            eventDO.setPointGroup(stringStringMap.get("point_group"));
            newEventList.add(eventDO);
        }



        kbReportMap.setEventList(newEventList);
        
        // 读取波形分析数据
        List<Map<String, Object>> waveAnalysis = parseWaveAnalysis(xmlPath);

        List<ModelDiagnoseDataDO> allList =  new ArrayList<>();
        List<WaveAnalysisDO> newWaveAnalysis = new ArrayList<>();
        for (int i = 0; i < waveAnalysis.size(); i++) {
            Map<String, Object> map = waveAnalysis.get(i);
            Object o = map.get("perSuite");
            List<ModelDiagnoseDataDO> list = (List<ModelDiagnoseDataDO>)map.get("perSuite");
            allList.addAll(list);
            WaveAnalysisDO waveAnalysisDO = new WaveAnalysisDO();

            waveAnalysisDO.setAbbr(map.get("abbr").toString());
            waveAnalysisDO.setTitle(map.get("title").toString());
            waveAnalysisDO.setBigTitle(map.get("bigTitle").toString());
            waveAnalysisDO.setPerSuite(list);
            newWaveAnalysis.add(waveAnalysisDO);
        }
        kbReportMap.setWaveAnalysis(newWaveAnalysis);
        allList.sort(Comparator.comparing(ModelDiagnoseDataDO::getSortFlag).thenComparing(ModelDiagnoseDataDO::getSuit));

        kbReportMap.setModelDiagnose(allList);

        //打印json格式
//        ObjectMapper mapper = new ObjectMapper();
//        JsonNode jsonArray = mapper.valueToTree(kbReportMap);
//
//        System.out.println(jsonArray);

//  自写
        Map<String, Object> map = convertToMap(kbReportMap);
        bulidKbWord(map,baseData.getFaultDesc(),templatePath,outputPath);



        
        System.out.println("✅ 已生成：" + outputPath +
                          "（事件 " + eventList.size() + " 条，含排序+合并；波形分析段 " + waveAnalysis.size() + " 个）");
    }
    /*
     * @description:
     * @date: 2025/10/27 22:36
     *
     * @param map 填充参数
     * @param faultDesc 设备描述
     * @param templatePath 模版地址
     * @param outputPath  输出地址
     *
     **/
    private void bulidKbWord(Map<String, Object> map, String faultDesc, String templatePath, String outputPath) throws IOException {
        //模板表格赋予格式
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        Configure configure = Configure.builder()
                .bind("eventList", policy)
                .bind("waveAnalysis", policy)
                .bind("modelDiagnose", policy)
                .build();
        ClassPathResource resource = new ClassPathResource(templatePath);
        if (!resource.exists()) {
            System.out.println("模板 不存在 ！！");
        }
        try (InputStream inputStream = resource.getInputStream()) {
            //创建临时文件,将模版拷贝到临时文件中
            File sourceFile = File.createTempFile(IdWorker.getIdStr(), "");
            FileUtil.writeFromStream(inputStream, sourceFile);
            try {
                //最终编译渲染并输出
                try (XWPFTemplate render = XWPFTemplate.compile(sourceFile, configure).render(map)) {
                    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
                        render.write(byteArrayOutputStream);

                        byte[] bytes = byteArrayOutputStream.toByteArray();
                        try (InputStream swapStream = new ByteArrayInputStream(bytes)) {
                            //文件名字
                            faultDesc = faultDesc + "评估报告" + ".docx";
                            saveWord(swapStream, faultDesc,outputPath);
                            byteArrayOutputStream.close();
                        }
                        render.close();
                    }
                }
            } catch (Exception e) {
                System.out.println("根据模版去生成文件异常{}");
                e.printStackTrace();
            }
        }

    }
    private String saveWord(InputStream swapStream, String fileName, String outputPath) throws IOException {
        try (InputStream inputStream1 = swapStream) {
            // 生成唯一文件名
            String nameUUid = UUID.randomUUID().toString().replace("-", "") + ".docx";
            // 创建 MockMultipartFile(<input type="file" name="...">的name属性；文件原始名；文件内容类型；流)
            MultipartFile file = new MockMultipartFile(
                    fileName,
                    nameUUid,
                    "application/docx",
                    inputStream1
            );

            long size = file.getSize();
            if (size == 0) {
                throw new IOException("文件大小为0");
            }
            BigDecimal fileSize = BigDecimal.valueOf(size / (1024.0));
            // 获取上传文件的原始名称
            String originalFilename = FilenameUtils.getName(file.getOriginalFilename());
            // 文件的后缀
            String fileExtension = StringUtils.getFilenameExtension(originalFilename);

            // 读取文件内容为字节数组
            byte[] fileBytes;

            try (InputStream inputStream = file.getInputStream()) {

                fileBytes = IOUtils.toByteArray(inputStream);

            }
            Path targetDir = Paths.get(outputPath);
            if (!Files.exists(targetDir)) {
                Files.createDirectories(targetDir);
            }
            Path targetPath = targetDir.resolve(fileName);
            try (InputStream byteArrayStream = new ByteArrayInputStream(fileBytes)) {
                Files.copy(byteArrayStream, targetPath, StandardCopyOption.REPLACE_EXISTING);
            }
            return "fileId";
        } catch (IOException e) {
            throw e;
        } catch (Exception e) {
            throw new IOException("Failed to save Word file", e);
        }

    }
    private Map<String, Object> convertToMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>();
        Class<?> clazz = obj.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }

    /**
     * 解析XML文件并提取数据到Map
     */
    public static ReportBasicsData parseXmlToMap(String xmlPath) throws Exception {
//        Map<String, Object> dataMap = new HashMap<>();
        ReportBasicsData reportBasicsData = new ReportBasicsData();

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new File(xmlPath));
        
        XPath xpath = XPathFactory.newInstance().newXPath();
        
        // 提取基本字段
        String stationName = getNodeText(doc, ".//station/name");
        String faultDesc = getNodeText(doc, ".//station/field/faultdesc");
        String operationMode = getNodeText(doc, ".//station/field/operation_mode/original");
        String voltageMode = getNodeText(doc, ".//station/field/voltage_mode/original");
        String dcpower = getNodeText(doc, ".//station/field/dcpower/original");
        String powerLoss = getNodeText(doc, ".//station/field/dcpower/power_loss");
        
        // 提取时间
        String firstTime = getNodeText(doc, ".//EventInfo/M2EventList[1]/time");
        String[] timeParts = parseEventTimes(firstTime);
        String eventDateYmd = timeParts[0];
        String eventDateTime = timeParts[1];


        reportBasicsData.setStationName(stationName);
        reportBasicsData.setFaultDesc(faultDesc);
        reportBasicsData.setOperationMode(operationMode);
        reportBasicsData.setVoltageMode(voltageMode);
        reportBasicsData.setDcpower(dcpower);
        reportBasicsData.setPowerLoss(powerLoss);
        reportBasicsData.setEventDateTime(eventDateTime);
        reportBasicsData.setEventDateYmd(eventDateYmd);


        
        return reportBasicsData;
    }
    
    /**
     * 解析事件列表
     */
    public static List<Map<String, String>> parseEventList(String xmlPath) throws Exception {
        List<Map<String, String>> events = new ArrayList<>();
        
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new File(xmlPath));
        
        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList nodeList = (NodeList) xpath.compile(".//EventInfo/M2EventList").evaluate(doc, XPathConstants.NODESET);
        
        for (int i = 0; i < nodeList.getLength(); i++) {
            Element eventElement = (Element) nodeList.item(i);
            
            String timeText = getNodeText(eventElement, "time");
            String systemId = getNodeText(eventElement, "SystemID");
            String mainCpu = getNodeText(eventElement, "MainCpu");
            String eventText = getNodeText(eventElement, "EventText");
            String pointGroup = getNodeText(eventElement, "PointGroup");
            
            double timeValue = 0.0;
            String hhmmssMs = "";
            
            if (!timeText.isEmpty()) {
                for (String fmt : new String[]{"yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd HH:mm:ss"}) {
                    try {
                        LocalDateTime dt = LocalDateTime.parse(timeText, DateTimeFormatter.ofPattern(fmt));
                        hhmmssMs = dt.format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS"));
                        timeValue = dt.getHour() * 3600.0 + dt.getMinute() * 60.0 + dt.getSecond() + dt.getNano() / 1_000_000_000.0;
                        break;
                    } catch (Exception e) {
                        // 尝试下一个格式
                    }
                }
                if (hhmmssMs.isEmpty()) {
                    hhmmssMs = timeText;
                }
            }

            Map<String, String> event = new HashMap<>();
            event.put("time", timeText);
            event.put("time_value", String.valueOf(timeValue));
            event.put("hhmmss_ms", hhmmssMs);
            event.put("system_id", systemId);
            event.put("main_cpu", mainCpu);
            event.put("event_text", eventText);
            event.put("point_group", pointGroup);
            
            events.add(event);
        }
        //TODO 这个部分看看需不需要。
        // 按时间排序
        events.sort(Comparator.comparingDouble(e -> Double.parseDouble(e.get("time_value"))));
        
        // 合并时间相近且内容相同的行（±3ms）
        List<Map<String, String>> merged = new ArrayList<>();
        for (Map<String, String> e : events) {
            if (merged.isEmpty()) {
                merged.add(e);
                continue;
            }
            
            Map<String, String> last = merged.get(merged.size() - 1);
            double time1 = Double.parseDouble(e.get("time_value"));
            double time2 = Double.parseDouble(last.get("time_value"));
            
            if (Math.abs(time1 - time2) <= 0.003 && 
                e.get("system_id").equals(last.get("system_id")) &&
                e.get("event_text").equals(last.get("event_text")) &&
                e.get("point_group").equals(last.get("point_group"))) {
                
                // 合并CPU
                Set<Character> cpus = new HashSet<>();
                for (char c : (last.get("main_cpu") + e.get("main_cpu")).toCharArray()) {
                    cpus.add(c);
                }
                StringBuilder cpuBuilder = new StringBuilder();
                cpus.stream().sorted().forEach(cpuBuilder::append);
                last.put("main_cpu", cpuBuilder.toString());
                
                // 更新时间值
                if (time1 > time2) {
                    last.put("time_value", e.get("time_value"));
                    last.put("hhmmss_ms", e.get("hhmmss_ms"));
                    last.put("time", e.get("time"));
                }
            } else {
                merged.add(e);
            }
        }
        
        return merged;
    }
    
    /**
     * 解析波形分析数据
     */
    public static List<Map<String, Object>> parseWaveAnalysis(String xmlPath) throws Exception {
        List<Map<String, Object>> sections = new ArrayList<>();
        
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new File(xmlPath));
        
        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList nodeList = (NodeList) xpath.compile(".//WaveInfo/WaveAnalysis/result").evaluate(doc, XPathConstants.NODESET);
        
        // 按首次出现顺序存储保护类型
        LinkedHashMap<String, Map<String, Object>> protections = new LinkedHashMap<>();
        Pattern secPattern = Pattern.compile("([^\n:]+?)\\(([A-Z]+)\\):\\s*\n"); // 移除Pattern.UNICODE
        
        for (int i = 0; i < nodeList.getLength(); i++) {
            Element res = (Element) nodeList.item(i);
            String name = getNodeText(res, "name");
            String contentRaw = getNodeText(res, "content");
            String content = contentRaw.replace("\\n", "\n");
            
            // 解析套别 (A/B/C)
            Matcher suiteMatcher = Pattern.compile("极\\d+极保护([ABC])套").matcher(name);
            String suite = null;
            if (suiteMatcher.find()) {
                suite = suiteMatcher.group(1);
            }
            
            // 扫描每一个段标题
            List<Map<String, String>> sectionsFound = new ArrayList<>();
            Matcher matcher = secPattern.matcher(content);
            int lastEnd = 0;
            
            while (matcher.find()) {
                // 如果有上一个段，设置其文本内容
                if (!sectionsFound.isEmpty()) {
                    Map<String, String> last = sectionsFound.get(sectionsFound.size() - 1);
                    String text = content.substring(lastEnd, matcher.start()).trim();
                    last.put("text", text);
                }
                
                // 创建新段
                Map<String, String> section = new HashMap<>();
                section.put("cn_title", matcher.group(1).trim());
                section.put("abbr", matcher.group(2).trim());
                section.put("text", "");
                sectionsFound.add(section);
                
                lastEnd = matcher.end();
            }
            
            // 处理最后一个段
            if (!sectionsFound.isEmpty()) {
                Map<String, String> last = sectionsFound.get(sectionsFound.size() - 1);
                String text = content.substring(lastEnd).trim();
                last.put("text", text);
            }
            
            // 写入protections
            for (Map<String, String> sec : sectionsFound) {
                String abbr = sec.get("abbr");
                String fullTitle = sec.get("cn_title") + "(" + abbr + ")";
                
                if (!protections.containsKey(abbr)) {
                    Map<String, Object> protection = new HashMap<>();
                    protection.put("title", fullTitle);
                    protection.put("per_suite", new HashMap<String, String>());
                    protections.put(abbr, protection);
                }
                
                if (suite != null) {
                    @SuppressWarnings("unchecked")
                    Map<String, String> perSuite = (Map<String, String>) protections.get(abbr).get("per_suite");
                    perSuite.put(suite, sec.get("text"));
                }
            }
        }
        int subIndex = 1;
        // 按首次出现顺序输出
        for (Map.Entry<String, Map<String, Object>> entry : protections.entrySet()) {
            Map<String, Object> section = new HashMap<>();
            section.put("abbr", entry.getKey());
            section.put("title", entry.getValue().get("title"));
//            section.put("per_suite", entry.getValue().get("per_suite"));

            //添加图片地址  标题信息等
            String sortFlag = "3" + subIndex;
            String bigTitle = "3." + subIndex + " " + section.get("title").toString();
            section.put("bigTitle", bigTitle);//3.1 直流线路行波保护(LPTW)
            // 添加A/B/C套分析结果
            @SuppressWarnings("unchecked")
            Map<String, String> perSuite = (Map<String, String>) entry.getValue().get("per_suite");

            List<ModelDiagnoseDataDO> modelDiagnoseDataDOList = new ArrayList<>();
            for (String suite : new String[]{"A", "B", "C"}) {
                if (perSuite.containsKey(suite)) {


                    ModelDiagnoseDataDO modelDiagnoseDataDO = new ModelDiagnoseDataDO();
                    modelDiagnoseDataDO.setDetailedInformation(perSuite.get(suite));
                    modelDiagnoseDataDO.setSuit(suite);
                    modelDiagnoseDataDO.setBigTitle(bigTitle);
                    modelDiagnoseDataDO.setSortFlag(sortFlag);


                    String smallTitle = "极1极保护" + suite + "套分析结果："; //极1极保护A套分析结果：
                    modelDiagnoseDataDO.setSmallTitle(smallTitle);
                    // 插入图片
                    String imgName = "PPR1" + suite + "_LINE_" + section.get("abbr").toString() + ".png";
                    String imgPath = "E:\\personCode\\LiJingJavaCodeAddress\\beforeJavaCodeSummary\\src\\main\\resources\\templates\\1\\" ;

                    File imgFile = new File(imgPath);
                    String fullImgPath = "NOT_FOUNT_IMAGE";
                    if (imgFile.exists()) {
                        fullImgPath = imgPath + imgName;
                        Path path = Paths.get(fullImgPath);


                        PictureRenderData pictureRenderData = new PictureRenderData(540, 500, PictureType.PNG, Files.readAllBytes(path));
                        modelDiagnoseDataDO.setPic(pictureRenderData);

                    }
                    modelDiagnoseDataDO.setFullImgPath(fullImgPath);
                    modelDiagnoseDataDOList.add(modelDiagnoseDataDO);
                }
            }
            modelDiagnoseDataDOList.sort(Comparator.comparing(ModelDiagnoseDataDO::getSuit));
            section.put("perSuite",modelDiagnoseDataDOList);
            subIndex++;
            sections.add(section);
        }

        return sections;
    }

    /**
     * 在文档中替换占位符
     */

    
    private static void replaceInParagraph(XWPFParagraph paragraph, Map<String, Object> replacements) {
        String text = paragraph.getText();
        if (text != null) {
            for (Map.Entry<String, Object> entry : replacements.entrySet()) {
                String placeholder = "{{" + entry.getKey() + "}}";
                if (text.contains(placeholder)) {
                    String value = entry.getValue() != null ? entry.getValue().toString() : "";
                    text = text.replace(placeholder, value);
                }
            }
            
            // 重新设置段落文本
            if (!text.equals(paragraph.getText())) {
                for (XWPFRun run : paragraph.getRuns()) {
                    run.setText("", 0);
                }
                if (!paragraph.getRuns().isEmpty()) {
                    paragraph.getRuns().get(0).setText(text, 0);
                } else {
                    paragraph.createRun().setText(text);
                }
            }
        }
    }
    
    /**
     * 在占位符位置插入事件表格
     */

    

    
    /**
     * 获取节点文本内容
     */
    private static String getNodeText(Document doc, String xpathExpr) throws Exception {
        XPath xpath = XPathFactory.newInstance().newXPath();
        return xpath.compile(xpathExpr).evaluate(doc).trim();
    }
    
    private static String getNodeText(Element parent, String tagName) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            return nodeList.item(0).getTextContent().trim();
        }
        return "";
    }
    
    /**
     * 解析事件时间
     */
    private static String[] parseEventTimes(String timeText) {
        if (timeText == null || timeText.trim().isEmpty()) {
            return new String[]{"", ""};
        }
        
        for (String fmt : new String[]{"yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd HH:mm:ss"}) {
            try {
                LocalDateTime dt = LocalDateTime.parse(timeText, DateTimeFormatter.ofPattern(fmt));
                String ymd = dt.getYear() + "年" + dt.getMonthValue() + "月" + dt.getDayOfMonth() + "日";
                String ymdHms = ymd + dt.getHour() + "时" + dt.getMinute() + "分" + dt.getSecond() + "秒";
                return new String[]{ymd, ymdHms};
            } catch (Exception e) {
                // 尝试下一个格式
            }
        }
        
        return new String[]{"", ""};
    }
}



